import {CaluAttrStr, CaluType, RewardType, SpecialEffectType, VestJson} from "../type/Type";
import {Util} from "./Util";
import {UnitController} from "../controller/UnitController";
import {BroadcastRequest, BroadcastType, ControllerNo, TimeControllerOpt} from "../controller/model/ControllerOpt";
import {TimeController} from "../controller/TimeController";
import {DataRouter} from "../frame/dataSource/DataRouter";
import {TaskController} from "../controller/TaskController";
import {AbilityEffectData, AttributeEnum, CastType1, HurtType, UnitAttribute} from "../frame/dataSource/DataModel";
import {DataRouterUtil} from "./router/DataRouterUtil";
import {AbilityController} from "../controller/AbilityController";
import {FinalKey} from "../constant/FinalConstant";
import Configer from "../frame/apiModel/config/Configer";
import {ControllerBroadcast} from "../controller/ControllerBroadcast";
import MathUtil from "../frame/codeAdapter/MathUtil";
import {Logger} from "../frame/apiModel/config/Logger";
import {UnitModel} from "../frame/apiModel/adapterModel/model3/UnitModel";
import {PlayerFactory} from "../frame/PlayerFactory";
import {UnitJson} from "../frame/apiModel/model/StoreJson";
import {ModelFactory} from "../frame/apiModel/adapterModel/model5/ModelFactory";
import {LocModel} from "../frame/apiModel/base/LocModel";
import {CodeUtil} from "../frame/codeAdapter/CodeUtil";
import UnitUtil from "./UnitUtil";
import {PlayerModel} from "../frame/apiModel/adapterModel/model4/PlayerModel";


export class TriggerUtil {
    static getTargetArr = (activeUnit: UnitModel, targetUnit: UnitModel | void, unitLoc: LocModel, spellLoc: LocModel, abilityEffectData: AbilityEffectData): UnitModel[] => {
        const targetArr: UnitModel[] = [];
        const isMine = abilityEffectData.mine;
        const range = abilityEffectData.range;
        const maxUnitNum = abilityEffectData.max_unit;
        if (!CodeUtil.isNullOrZero(range)) {
            let filter: (unit: UnitModel) => boolean;
            const tempTargetArr: UnitModel[] = [];
            const activePlayer = PlayerFactory.getInstance().getUnitOwner(activeUnit)
            filter = (unit: UnitModel): boolean => {
                const tempPlayer = PlayerFactory.getInstance().getUnitOwner(unit)
                let checkCamp = !tempPlayer.isPlayerAlly(activePlayer);
                if (!CodeUtil.isNullOrZero(isMine)) {
                    checkCamp = tempPlayer.isPlayerAlly(activePlayer);
                }
                const isAlive = DataRouterUtil.checkUnitUseAttr(unit);
                return checkCamp && isAlive
            }

            const pushFun = (arr: UnitModel[], unit: UnitModel) => {
                const index = arr.indexOf(unit);
                if (index === -1) {
                    arr.push(unit);
                }
            }

            if (unitLoc?.isVaild()) {
                ModelFactory.getInstance().mapUnitInRange(unitLoc, range,
                    (unit) => {
                        if (filter(unit)) {
                            pushFun(tempTargetArr, unit);
                        }
                    }
                )
            }

            if (spellLoc?.isVaild()) {
                ModelFactory.getInstance().mapUnitInRange(spellLoc, range,
                    (unit) => {
                        if (filter(unit)) {
                            pushFun(tempTargetArr, unit);
                        }
                    }
                )
            }

            if (!CodeUtil.isNullOrZero(maxUnitNum) && tempTargetArr.length > maxUnitNum) {
                for (let i = 0; i < maxUnitNum; i ++) {
                    const currentLen = tempTargetArr.length;
                    const random = activePlayer.getRandomInt(0, currentLen);
                    const retArr = tempTargetArr.splice(random, 1);
                    targetArr.push(...retArr);
                }
            } else {
                targetArr.push(...tempTargetArr);
            }
        } else {
            if (!CodeUtil.isNullOrZero(isMine)) {
                if (DataRouterUtil.checkUnitUseAttr(activeUnit)) {
                    targetArr.push(activeUnit)
                }
            } else {
                if (DataRouterUtil.checkUnitUseAttr(targetUnit)) {
                    targetArr.push(targetUnit as UnitModel)
                }
            }
        }
        return targetArr;
    }

    static checkEffectLimit = (activeUnit: UnitModel, abilityEffectData: AbilityEffectData) => {
        const condition = abilityEffectData.condition;
        const conditionArr = CodeUtil.getArrBySplit(condition);
        const player = PlayerFactory.getInstance().getUnitOwner(activeUnit);
        const ret = TaskController.getInstance().checkConditions(activeUnit, conditionArr, undefined, player);
        return ret.success;
    }

    static useAbilityEffect = (activeUnit: UnitModel, targetUnit: UnitModel | void, abilityEffectData: AbilityEffectData, spellLoc: LocModel, effectLevel: number) => {
        if (!CodeUtil.isNullOrZero(effectLevel)) {
        } else {
            return;
        }
        let newActiveUnit = activeUnit;
        const effectId = abilityEffectData.id;
        const effectsAlways = abilityEffectData.effectsAlways;
        const recordCheck = AbilityController.getInstance().addAbilityLock(newActiveUnit, abilityEffectData);
        const activePlayer = PlayerFactory.getInstance().getUnitOwner(newActiveUnit);
        if (recordCheck) {
        } else {
            Logger.toastSkill('超出锁上限', activePlayer);
            return;
        }

        let randomInt = activePlayer.getRandomInt(1, 100);

        const probability = abilityEffectData.probability;
        const fail_tips = abilityEffectData.fail_tips;
        // 计算成功几率
        const checkLimit = TriggerUtil.checkEffectLimit(newActiveUnit, abilityEffectData);
        if (checkLimit && probability >= randomInt) {
        } else {
            Logger.toastProduct(fail_tips, activePlayer);
            return false;
        }

        let locUnVaild = false;
        if (spellLoc.isVaild()) {
        } else {
            locUnVaild = true;
        }


        let spellTempLoc = spellLoc;
        if (locUnVaild) {
            spellTempLoc = activeUnit.loc;
        }

        Logger.toastSkill(`释放几率: ${probability}`, activePlayer);
        Logger.toastSkill(`释放随机数: ${randomInt}`, activePlayer);

        // bRepeat 用来防止技能特效重复显示
        const abilityCallBack = function (bRepeatNum: number = 1, sumNum: number = 1) {
            if (activeUnit?.isValid()) {
            } else {
                return;
            }

            if (locUnVaild) {
                const reflushLoc = abilityEffectData.reflushLoc;
                if (!CodeUtil.isNullOrZero(reflushLoc)) {
                    spellTempLoc = activeUnit.loc;
                }
            }

            let targetLoc = targetUnit && targetUnit.loc;

            const targetLocType = abilityEffectData.targetLocType;
            if (!CodeUtil.isNullOrZero(targetLocType)) {
                targetLoc = activeUnit.loc;
            }

            const ret = UnitUtil.getAttribute(newActiveUnit);
            const currentAttr = ret.newestAttribute;
            // 计算技能消耗
            const cosumeAttr = ret.subExtraAttr;
            const whiteAttr = ret.whiteAttr;

            if (currentAttr) {
            } else {
                return;
            }
            const targetUnitArr = TriggerUtil.getTargetArr(newActiveUnit, targetUnit, targetLoc, spellTempLoc, abilityEffectData);
            Logger.toastSkill(`----------------------------------`, activePlayer);
            if (!CodeUtil.isNullOrZero(abilityEffectData.txt)) {
                Logger.toastSkill(`启用技能效果: ${abilityEffectData.txt}`, activePlayer);
            }

            const cosumeTypes = abilityEffectData.consume;
            const cosumeTypeArrs = CodeUtil.getArrBySplit(cosumeTypes)
            const consumption_percentages = abilityEffectData.consumption_percentage
            const consumption_percentageArrs = CodeUtil.getArrBySplit(consumption_percentages)
            const consumption_values = abilityEffectData.consumption_value
            const consumption_valueArrs = CodeUtil.getArrBySplit(consumption_values)

            for (let i = 0; i < cosumeTypeArrs.length; i++) {
                const cosumeType = DataRouterUtil.getNumByArr(cosumeTypeArrs, i);
                if (!CodeUtil.isNullOrZero(cosumeType)) {
                } else {
                    continue;
                }
                const consumption_percentage = DataRouterUtil.getNumByArr(consumption_percentageArrs, i);
                const consumption_value = DataRouterUtil.getNumByArr(consumption_valueArrs, i);
                const ret = TriggerUtil.abilityCosume
                (
                    newActiveUnit,
                    currentAttr,
                    cosumeAttr,
                    cosumeType,
                    consumption_percentage,
                    consumption_value,
                    effectId,
                );
                if (!ret) {
                    if (abilityEffectData.fail_tips) {
                        Logger.toastProduct(abilityEffectData.fail_tips);
                    }
                    return;
                }
            }
            let num = targetUnitArr.length;
            Logger.toastSkill(`选中单位数: ${num}`, activePlayer);


            const animation = abilityEffectData.animation;
            if (!CodeUtil.isNullOrZero(animation)) {
                activeUnit.setAnimation(animation);
            }


            // 使用者特效
            if (bRepeatNum === 1 || !CodeUtil.isNullOrZero(effectsAlways)) {
                const self_effects = abilityEffectData.self_effects;
                const self_effects_time = abilityEffectData.self_effects_time;
                const self_effects_point = abilityEffectData.self_effects_point;
                const self_effects_scale = abilityEffectData.self_effects_scale;
                if (self_effects) {
                    TimeController.addSpecialEffectByResourceIdFun(newActiveUnit, self_effects, self_effects_time, spellTempLoc, self_effects_point, SpecialEffectType.unit, self_effects_scale);
                }

                const self_point_effects = abilityEffectData.self_point_effects;
                const self_point_effects_time = abilityEffectData.self_point_effects_time;
                const self_point_effects_scale = abilityEffectData.self_point_effects_scale;
                if (self_point_effects) {
                    TimeController.addSpecialEffectByResourceIdFun(newActiveUnit, self_point_effects, self_point_effects_time, newActiveUnit.loc, undefined, SpecialEffectType.point, self_point_effects_scale);
                }

                // 目标点特效
                const point_effects = abilityEffectData.point_effects;
                const point_effects_time = abilityEffectData.point_effects_time;
                const point_effects_scale = abilityEffectData.point_effects_scale;
                if (point_effects) {
                    TimeController.addSpecialEffectByResourceIdFun(newActiveUnit, point_effects, point_effects_time, spellTempLoc, undefined, SpecialEffectType.point, point_effects_scale);
                }
            }

            const summon_id = abilityEffectData.summon_id;
            if (summon_id) {
                let summondLoc = activeUnit.loc;
                if (spellTempLoc.isVaild()) {
                    summondLoc = spellTempLoc;
                }
                TriggerUtil.abilitySummon(newActiveUnit, abilityEffectData, summondLoc, currentAttr);
            }

            let hurtType;
            if (!CodeUtil.isNullOrZero(abilityEffectData.harm_type)) {
                hurtType = abilityEffectData.harm_type;
            } else {
                hurtType = HurtType.spell;
            }
            // 如果是马甲释放的技能就找到召唤马甲的单位，根据其属性计算伤害等效果。
            const vestJson = UnitUtil.getVestJson(newActiveUnit);
            let bVest = false;
            if (vestJson) {
                // todo 暂时对马甲释放的技能不使用技能效果
                Logger.toastSkill(`马甲释放`, activePlayer);
                return;
            } else {
                const vestAbilityId = abilityEffectData.vest;
                if (vestAbilityId) {
                    bVest = !!vestAbilityId;
                    Logger.toastSkill(`启动马甲技能`, activePlayer);
                    TriggerUtil.abilityVest(newActiveUnit, targetUnitArr, spellTempLoc, vestAbilityId, effectId, hurtType, effectLevel);
                } else {
                    Logger.toastSkill(`非马甲释放`, activePlayer);
                }
            }

            let bAdd = false;

            targetUnitArr.forEach(
                (value, index, array) => {
                    const unit = value;

                    if (DataRouterUtil.checkUnitUseAttr(unit)) {
                    } else {
                        return;
                    }

                    const targetRet = UnitUtil.getAttribute(unit);
                    const targetAttr = targetRet.newestAttribute;
                    const targetSubAttr = targetRet.subExtraAttr;
                    const targetWhiteAttr = targetRet.whiteAttr;
                    let hurtValue = UnitUtil.abilityHurtGetValueByEffectData(newActiveUnit, targetUnit, currentAttr, targetAttr, effectId, effectLevel);

                    // 目标单位特效 ---------------------------------------------------------------------------------------------------------------------------
                    if (bRepeatNum === 1 || !CodeUtil.isNullOrZero(effectsAlways)) {
                        const target_effects = abilityEffectData.target_effects;
                        const target_effects_time = abilityEffectData.target_effects_time;
                        const target_effects_point = abilityEffectData.target_effects_point;
                        const target_effects_scale = abilityEffectData.target_effects_scale;
                        if (target_effects) {
                            TimeController.addSpecialEffectByResourceIdFun(unit, target_effects, target_effects_time, spellTempLoc, target_effects_point, SpecialEffectType.unit, target_effects_scale);
                        }
                    }

                    TriggerUtil.abilityHurt(newActiveUnit, unit, abilityEffectData.harm_target_attribute, currentAttr, targetAttr, hurtValue, hurtType, bVest, effectId, targetSubAttr);

                    // 计算属性增益 ----------------------------------------------------------------------------------------------------------------------
                    // 计算属性增益时需要用单位原值计算
                    let attribute = new UnitAttribute();
                    const addTime = abilityEffectData.add_time;
                    const targetAdds = abilityEffectData.add_target;
                    const targetAddArr = CodeUtil.getArrBySplit(targetAdds);
                    const adds = abilityEffectData.add;
                    const addArr = CodeUtil.getArrBySplit(adds);
                    const addValues = abilityEffectData.add_value;
                    const addValueArr = CodeUtil.getArrBySplit(addValues);
                    const addPercentages = abilityEffectData.add_percentage;
                    const addPercentagesArr = CodeUtil.getArrBySplit(addPercentages);
                    const targetAddIsMine = abilityEffectData.add_source_isMine;
                    const targetAddIsMineArr = CodeUtil.getArrBySplit(targetAddIsMine);


                    let otherNewestAttr = currentAttr;

                    // const effectDatas = DataRouter.getAbilityEffectDatas();
                    // const len = effectDatas.length;
                    // for (let i = len - 1; i >= 0; i--) {
                    //     const tempEffectData = effectDatas[i];
                    //     const tempEffectId = tempEffectData.id;
                    //     const abilityAttr = AbilityController.getInstance().getAbilityAttributes(newActiveUnit, tempEffectId);
                    //     if (abilityAttr) {
                    //         otherNewestAttr = Util.sumUnitAttribute(otherNewestAttr, abilityAttr, CaluType.sub);
                    //     }
                    //     if (effectId === tempEffectId) {
                    //         break;
                    //     }
                    // }

                    let addTimes = 1;
                    // const addUnit = abilityEffectData.addunit;
                    // const addUnitValue = abilityEffectData.addunit_value;
                    // const addUnitPercentage = abilityEffectData.addunit_percentage;
                    // let addTimes = TriggerUtil.abilityAddGetTimes
                    // (
                    //     newActiveUnit,
                    //     currentAttr,
                    //     addUnit,
                    //     addUnitValue,
                    //     addUnitPercentage,
                    // )
                    Logger.toastSkill(`增益N次: ${addTimes}`, activePlayer)
                    for (let i = 0; i < targetAddArr.length; i ++) {
                        const targetAdd = DataRouterUtil.getNumByArr(targetAddArr, i);
                        const add = DataRouterUtil.getNumByArr(addArr, i);
                        const addValue = DataRouterUtil.getNumByArr(addValueArr, i);
                        const addPercentage = DataRouterUtil.getNumByArr(addPercentagesArr, i);
                        const targetAddIsMine = DataRouterUtil.getNumByArr(targetAddIsMineArr, i);
                        if (!CodeUtil.isNullOrZero(targetAdd)) {
                            const tempAttr = new UnitAttribute();
                            // 根据属性增益单位计算属性增益次数
                            // 该方法中修改attribute
                            TriggerUtil.abilityAddChangeAttribute
                            (
                                unit,
                                activePlayer,
                                tempAttr,
                                otherNewestAttr,
                                targetAttr,
                                targetAdd,
                                add,
                                addValue,
                                addPercentage,
                                addTimes,
                                effectLevel,
                                targetAddIsMine,
                                effectId
                            );
                            bAdd = true;
                            attribute = Util.sumUnitAttribute(attribute, tempAttr, CaluType.add);
                        }
                    }
                    const thefts = abilityEffectData.theft;
                    const theftArr = CodeUtil.getArrBySplit(thefts);
                    const theftTargetAttributes = abilityEffectData.theft_target_attribute;
                    const theftTargetAttributeArr = CodeUtil.getArrBySplit(theftTargetAttributes);
                    const theftValues = abilityEffectData.theft_value;
                    const theftValueArr = CodeUtil.getArrBySplit(theftValues);
                    const theftPercentages = abilityEffectData.theft_percentage;
                    const theftPercentageArr = CodeUtil.getArrBySplit(theftPercentages);

                    const theftTargetIsMine = abilityEffectData.theft_target_isMine;
                    const theftTargetIsMineArr = CodeUtil.getArrBySplit(theftTargetIsMine);

                    const theft_source_isMine = abilityEffectData.theft_source_isMine;
                    const theft_source_isMineArr = CodeUtil.getArrBySplit(theft_source_isMine);

                    let bTheft = false;

                    for (let i = 0; i < theftArr.length; i ++) {
                        const theft =  DataRouterUtil.getNumByArr(theftArr, i);
                        const theftTargetAttribute =  DataRouterUtil.getNumByArr(theftTargetAttributeArr, i);
                        const theftValue =  DataRouterUtil.getNumByArr(theftValueArr, i);
                        const theftPercentage =  DataRouterUtil.getNumByArr(theftPercentageArr, i);
                        const theftTargetIsMine =  DataRouterUtil.getNumByArr(theftTargetIsMineArr, i);
                        const theftSourceIsMine =  DataRouterUtil.getNumByArr(theft_source_isMineArr, i);
                        if (!CodeUtil.isNullOrZero(theft)) {
                            if (!CodeUtil.isNullOrZero(theftTargetIsMine)) {
                                TriggerUtil.abilityTheftChangeAttribute
                                (
                                    activeUnit,
                                    activePlayer,
                                    targetSubAttr,
                                    targetAttr,
                                    targetAttr,
                                    targetWhiteAttr,
                                    theft,
                                    theftTargetAttribute,
                                    theftValue,
                                    theftPercentage,
                                    effectLevel,
                                    theftSourceIsMine,
                                    effectId
                                );
                            } else {
                                TriggerUtil.abilityTheftChangeAttribute
                                (
                                    unit,
                                    activePlayer,
                                    cosumeAttr,
                                    currentAttr,
                                    targetAttr,
                                    whiteAttr,
                                    theft,
                                    theftTargetAttribute,
                                    theftValue,
                                    theftPercentage,
                                    effectLevel,
                                    theftSourceIsMine,
                                    effectId
                                );
                            }
                            bTheft = true;
                        }
                    }
                    // 为了保证被动技能效果可以持续，这里稍微延长一点时间
                    let abilityAttr;
                    if (bAdd) {
                        let intervalEffectNum = 0;
                        if (!CodeUtil.isNullOrZero(addTime)) {
                            intervalEffectNum = addTime;
                        }
                        abilityAttr = attribute;

                        AbilityController.getInstance().addAbilityAttributes(unit, effectId, intervalEffectNum, abilityAttr);
                    }
                    if (bAdd || bTheft) {
                        const request: BroadcastRequest = { broadcastType: BroadcastType.addCaluTaskByUnit, controllerNo: ControllerNo.UnitController, data: { unit: unit, caluAttrStr: CaluAttrStr.effect } }
                        ControllerBroadcast.getInstance().broadcast(request);
                    }
                }
            )
            const request: BroadcastRequest = { broadcastType: BroadcastType.addCaluTaskByUnit, controllerNo: ControllerNo.UnitController, data: { unit: activeUnit, caluAttrStr: CaluAttrStr.effect } }
            ControllerBroadcast.getInstance().broadcast(request);
            // 技能施放成功提示
            const succeed_tips = abilityEffectData.succeed_tips;
            if (succeed_tips) {
                Logger.toastProduct(succeed_tips, activePlayer)
            }
            Logger.toastSkill(`----------------------------------`, activePlayer)
            // 技能效果表奖励
            TriggerUtil.effectReward(newActiveUnit, targetUnit, abilityEffectData, spellTempLoc);
            // 递归调用回调效果
            TriggerUtil.callBackIds(newActiveUnit, targetUnit, abilityEffectData, spellTempLoc, effectLevel);
        }
        const delay_time = abilityEffectData.delay_time;
        const time_duration = abilityEffectData.time_duration;
        // 如果技能间隔为0，则技能只触发一次
        let interval = 0;
        if (!CodeUtil.isNullOrZero(abilityEffectData.interval)) {
            interval = abilityEffectData.interval;
        }
        let periodic = 1;
        if (!CodeUtil.isNullOrZero(interval)) {
            periodic = time_duration / interval;
        }
        if (periodic) {
            periodic = MathUtil.floor(periodic);
        }
        const durationCallBack = function () {
            Logger.toastSkill(`触发技能效果`, activePlayer)
            let bRepeatNum = 0;
            const fun = () => {
                bRepeatNum = bRepeatNum + 1
                abilityCallBack(bRepeatNum, periodic);
            }


            fun();
            if (periodic > 1) {
                Logger.toastSkill(`启用循环触发，循环间隔:${periodic}`, activePlayer)
                const timerOpt = new TimeControllerOpt(undefined, fun, periodic - 1);
                TimeController.getInstance().startTimer({time: interval, opt: timerOpt});
            }
        }
        const frequency = abilityEffectData.frequency;
        const bCheck = AbilityController.getInstance().checkFrequency(newActiveUnit, effectId, frequency);
        if (bCheck) {
            if (!CodeUtil.isNullOrZero(delay_time)) {
                Logger.toastSkill(`延迟触发，延迟时间:${delay_time}`, activePlayer)
                Logger.toastSkill(`频率:${frequency}`, activePlayer)
                const timerOpt = new TimeControllerOpt(undefined, durationCallBack, 1);
                TimeController.getInstance().startTimer({time: delay_time, opt: timerOpt});
            } else {
                durationCallBack();
            }
        }
    }
    static effectReward = (activeUnit: UnitModel, targetUnit: UnitModel | void, abilityEffectData: AbilityEffectData, spellLoc: LocModel) => {
        const rewardId = abilityEffectData.reward;
        if (rewardId) {
            TaskController.getInstance().reward(activeUnit, targetUnit, RewardType.bag, rewardId)
        }
    }
    static callBackIds = (activeUnit: UnitModel, targetUnit: UnitModel | void, abilityEffectData: AbilityEffectData, spellLoc: LocModel, effectLevel: number) => {
        // 递归调用回调效果
        const callBackIds = abilityEffectData.effect_callback;
        const player = PlayerFactory.getInstance().getUnitOwner(activeUnit)
        if (callBackIds) {
        } else {
            return;
        }
        const callBackWeight = abilityEffectData.callbackWeight;
        const callBackIdArr = CodeUtil.getArrBySplit(callBackIds);
        if (callBackWeight) {
            const callBackWeightArr = CodeUtil.getArrBySplit(callBackWeight);
            let sumWeight = 0;
            const callBackRets: { id: string, weight: number, probability: number }[] = [];
            for (let i = 0; i < callBackWeightArr.length; i++) {
                const id = callBackIdArr[i];
                const weight = callBackWeightArr[i];
                const numWeight = MathUtil.toNumber(weight);
                sumWeight = sumWeight + numWeight;
                const callBackRet = { id: id, weight: numWeight, probability: 0 };
                callBackRets.push(callBackRet);
            }
            let retCallBack = DataRouterUtil.getDataModelByWeight(player, callBackRets, 1);
            if (retCallBack && retCallBack[0]) {
                const callBackId = retCallBack[0].id;
                const effectData = DataRouter.getEffectByEffectId(callBackId);
                if (effectData) {
                    TriggerUtil.useAbilityEffect(activeUnit, targetUnit, effectData, spellLoc, effectLevel);
                }
            }
        } else {
            for (let i = 0; i < callBackIdArr.length; i++) {
                const callBackId = callBackIdArr[i];
                const effectData = DataRouter.getEffectByEffectId(callBackId);
                if (effectData) {
                    TriggerUtil.useAbilityEffect(activeUnit, targetUnit, effectData, spellLoc, effectLevel);
                }
            }
        }
    }
    static abilitySummon = (activeUnit: UnitModel, abilityEffectData: AbilityEffectData, unitLoc: LocModel, currentAttr: UnitAttribute) => {
        const player = PlayerFactory.getInstance().getUnitOwner(activeUnit);
        Logger.toastSkill(`召唤单位效果启动: start`, player)
        const allNum = player.allFood;
        const currentNum = player.usedFood;
        const otherNum = allNum - currentNum;
        const summon_id = abilityEffectData.summon_id;
        let unitId = '';
        if (summon_id) {
            unitId = summon_id;
        }
        let unitData = DataRouter.getUnitDataByUnitId(unitId);
        let useFood = 0;
        if (unitData && unitData.fused) {
            useFood = unitData.fused;
        }
        const retFood = otherNum - useFood;
        if (retFood < 0) {
            Logger.toastProduct(`召唤数量已经达到最大`, player)
            return false;
        }
        const num = abilityEffectData.summon_num;
        const usePercentages = abilityEffectData.summon_percentage;
        const usePercentageArrs = CodeUtil.getArrBySplit(usePercentages);
        const unitJson: UnitJson = { id: summon_id, e: 0 }
        const unitArr = UnitController.getInstance().createUnit(num, unitJson, player, unitLoc, 0);
        Logger.toastSkill(`召唤单位数: ${unitArr.length}`, player)
        const summons = abilityEffectData.summon;
        const summonArrs: string[] = CodeUtil.getArrBySplit(summons);
        const corresponds = abilityEffectData.summon_correspond;
        const correspondArrs: string[] = CodeUtil.getArrBySplit(corresponds);
        const values = abilityEffectData.summon_value;
        const valueArrs: string[] = CodeUtil.getArrBySplit(values);
        const summonTime = abilityEffectData.summon_unit_time;

        const summond_effects = abilityEffectData.summon_effects;
        const summond_effects_time = abilityEffectData.summon_effects_time;
        const summond_effects_scale = abilityEffectData.summon_effects_scale;

        for (let j = 0; j < unitArr.length; j++) {
            const unit = unitArr[j];
            const extraAttr = new UnitAttribute();
            for (let i = 0; i < summonArrs.length; i++) {
                const numSummon = DataRouterUtil.getNumByArr(summonArrs, i);
                const numCorrespond = DataRouterUtil.getNumByArr(correspondArrs, i);
                let numValue = DataRouterUtil.getNumByArr(valueArrs, i);
                const usePercentage = DataRouterUtil.getNumByArr(usePercentageArrs, i);
                Logger.toastSkill(`目标属性: ${AttributeEnum[numSummon]}`, player)
                Logger.toastSkill(`参照属性: ${AttributeEnum[numCorrespond]}`, player)
                Logger.toastSkill(`新属性: ${numValue}`, player)
                if (!CodeUtil.isNullOrZero(usePercentage)) {
                    const currentValue = Util.getTargetAttributeEnumByHero(numCorrespond, currentAttr, activeUnit);
                    Logger.toastSkill(`参照对象属性: ${currentValue}`, player)
                    numValue = currentValue * (numValue / 100);
                    Logger.toastSkill(`使用百分比后新属性: ${numValue}`, player)
                }
                Logger.toastSkill(`效果表增益属性值: ${numValue}`, player)
                extraAttr[numSummon] = numValue + extraAttr[numSummon]
            }
            const effectId = abilityEffectData.id;
            const foreverPeriodic = Configer.getFinal(FinalKey.foreverPeriodic) as number;
            AbilityController.getInstance().addAbilityAttributes(unit, effectId, foreverPeriodic, extraAttr);
            if (!CodeUtil.isNullOrZero(summonTime)) {
                const waterId = Configer.getFinal(FinalKey.water) as string;
                unit.applyTimedLife(waterId, summonTime);
            } else {
                UnitController.getInstance().reflushSummonedByUnitId(player, summon_id, num);
            }

            if (summond_effects) {
                const tempLoc = unit.loc;
                TimeController.addSpecialEffectByResourceIdFun(unit, summond_effects, summond_effects_time, tempLoc, undefined, SpecialEffectType.point, summond_effects_scale);
            }

            if (unit.invulnerable) {
            } else {
                unit.invulnerable = true;
                const durationCallBack = () => {
                    unit.invulnerable = false;
                }
                const timerOpt = new TimeControllerOpt(undefined, durationCallBack, 1);
                TimeController.getInstance().startTimer({time: 1, opt: timerOpt});
            }

            const summon_follow = abilityEffectData.summon_follow;
            const usePatro = !CodeUtil.isNullOrZero(summon_follow)

            UnitController.getInstance().addSummoneds(unit, activeUnit, usePatro);
            UnitController.getInstance().addUnitCombinationByUnit(unit);
            UnitController.getInstance().addCaluAttributeTaskByUnit(unit, false, '召唤物属性');
        }
        Logger.toastSkill(`召唤单位效果启动: end`, player)
    }
    static abilityCosume = (activeUnit: UnitModel, currentAttr: UnitAttribute, cosumeAttr: UnitAttribute, targetAttr: AttributeEnum, percentage: number, value: number, effectId: string): boolean => {
        const player = PlayerFactory.getInstance().getUnitOwner(activeUnit);
        Logger.toastSkill(`技能消耗：start`, player)
        let bAlways = true;
        // 本来提供了对属性系统单位消耗属性的兼容，现在改成直接减
        // const isHero = UnitController.getInstance().isAttributeUnit(activeUnit);
        // if (isHero) {
        //     bAlways = false;
        // }
        const ret = Util.caluAbilityAttr(activeUnit, player, currentAttr, currentAttr, cosumeAttr, targetAttr, targetAttr, value, percentage, CaluType.sub, false, bAlways, effectId);
        if (ret) {
        } else {
            return false
        }
        Logger.toastSkill(`技能消耗：end`, player)
        return true;
    }
    static abilityHurt = (activeUnit: UnitModel, targetUnit: UnitModel, hartTargetAttr: AttributeEnum, attackAttr: UnitAttribute, attackedAttr: UnitAttribute, hurtValue: number, hurtType: HurtType, bVest: boolean, effectId: string, subAttr: UnitAttribute) => {
        let newHurtValue = hurtValue;
        const player = PlayerFactory.getInstance().getUnitOwner(activeUnit);
        Logger.toastSkill(`原始伤害${newHurtValue}`, player)
        if (hurtType === HurtType.treat) {
            newHurtValue = -newHurtValue;
        }
        if (!CodeUtil.isNullOrZero(newHurtValue)) {
            const isDead = !targetUnit?.isAlive();
            if (isDead) {
                return;
            }
            if (!CodeUtil.isNullOrZero(newHurtValue)) {
                if (hartTargetAttr === AttributeEnum.life) {
                    if (bVest) {
                    } else {
                        if (newHurtValue > 0) {
                            // 这里造成伤害后会走到自定义战斗系统中, 自定义战斗系统对伤害进行计算暴击与伤害显示
                            const ret = UnitUtil.getUnitHurt(activeUnit, newHurtValue, attackAttr, attackedAttr, hurtType);
                            const hurtNum = ret.hurt;
                            const bCh = ret.bCh;
                            const bHit = ret.bHit;
                            const bBlock = ret.bBlock;
                            const bloodSuck = ret.bloodSuck;
                            const thorns = ret.thorns;
                            const realH = ret.realH;
                            UnitUtil.showHurtNum(hurtNum, activeUnit, targetUnit, hurtType, bCh, bHit, bBlock, bloodSuck, thorns, realH);
                            UnitUtil.correctHurt(activeUnit, targetUnit, hurtType, hurtNum, 0, bloodSuck, bHit, thorns);
                        } else {
                            const hurtNum = newHurtValue;
                            UnitUtil.showHurtNum(hurtNum, activeUnit, targetUnit, hurtType, false, true, false, 0, 0, 0);
                            UnitUtil.correctHurt(activeUnit, targetUnit, hurtType, hurtNum, 0, 0, true, 0);
                        }
                    }
                } else {
                    let bAlways = true;
                    // 伤害的属性现在变成直接消减
                    // const isHero = UnitController.getInstance().isAttributeUnit(targetUnit);
                    // if (isHero) {
                    //     bAlways = false;
                    // }
                    Util.caluAbilityAttr(targetUnit, player, subAttr, subAttr, subAttr, hartTargetAttr, hartTargetAttr, newHurtValue, 0, CaluType.sub, true, bAlways, effectId);
                }
            }
            Logger.toastSkill(`技能伤害：end`, player)
        }
    }

    static abilityVest = (activeUnit: UnitModel, targetGroup: UnitModel[], spellLoc: LocModel, abilityId: string, effectId: string, hurtType: HurtType, effectLevel: number) => {
        TriggerUtil.activeUseAbility(activeUnit, abilityId, targetGroup, [spellLoc], effectId, hurtType, effectLevel, true);
    }
    // 创建技能马甲
    // 使用技能的单位、技能应当造成的伤害、马甲需要使用的技能
    static createAbilityVest = (activeUnit: UnitModel, vestAbilityId: string, effectId: string, effectLevel: number, hurtType: HurtType): UnitModel => {
        const player = PlayerFactory.getInstance().getUnitOwner(activeUnit);
        Logger.toastSkill(`新建技能马甲`, player)
        const vestId = Configer.getFinal(FinalKey.vestId) as string;
        const loc = activeUnit.loc;
        const unitJson: UnitJson = { id: vestId, e: 0 }
        const units = UnitController.getInstance().createUnit(1, unitJson, player, loc, 0);
        let vest = units[0];
        const vestJson: VestJson = { vestId, effectId, effectLevel, sourceUnit: activeUnit, hurtType };
        UnitController.getInstance().bindVestUser(vest, vestJson);
        Logger.toastSkill(`马甲添加技能${vestAbilityId}`, player)
        vest.addAbility(vestAbilityId);
        vest.show = false;
        const deleteUnitFun = function () {
            vest.kill();
        }
        // todo xlsx 删除马甲单位的间隔时间
        const opt = new TimeControllerOpt(undefined, deleteUnitFun, 1);
        TimeController.getInstance().startTimer({ opt, time: 10 })
        return vest;
    }
    // 通过技能数据获取主动释放技能的方法
    // 根据传入abilityId的技能父技能判断调用哪个接口使单位主动释放技能
    // activeUnit是使用技能召唤马甲的单位
    // targetGroup是activeUnit使用技能选中的所有单位
    // spellLoc是释放技能的点，释放以点为目标的技能时需要传入这个值
    static activeUseAbility = (activeUnit: UnitModel, abilityId: string, targetArr: UnitModel[], targetLocArr: LocModel[], effectId: string, hurtType: HurtType, effectLevel: number, useVestAbility: boolean = true) => {
        const player = PlayerFactory.getInstance().getUnitOwner(activeUnit);
        if (activeUnit?.isAliveInBattle()) {
        } else {
            Logger.toastSkill(`单位已死亡，停止释放`, player)
            return;
        }
        let unit = activeUnit;
        let vestId, strOrder, cast_type1;
        const abilityData = DataRouter.getAbilityDataById(abilityId);
        if (abilityData) {
        } else {
            Logger.toastError(`技能 ${abilityId} 不存在, 无法主动使用`)
            return;
        }
        if (useVestAbility) {
            vestId = abilityId;
            Logger.toastSkill(`vestId: ${vestId}`, player)
            if (vestId) {
            } else {
                Logger.toastSkill(`马甲技能为空`, player)
                return;
            }
        }
        cast_type1 = abilityData.cast_type1;
        strOrder = abilityData.Order;
        Logger.toastSkill(`命令Id: ${strOrder}`, player)
        // if (parentId === 'AHtb') {
        //     strOrder = OrderId2String(OrderId.Thunderbolt)
        // } else if (parentId === 'AHtc' ) {
        //     strOrder = OrderId2String(OrderId.Thunderclap)
        // } else if (parentId === 'AHbz') {
        //     strOrder = OrderId2String(OrderId.Blizzard)
        // }
        if (cast_type1 === CastType1.null) {
            Logger.toastSkill(`马甲原地释放`, player)
            if (vestId) {
                unit = TriggerUtil.createAbilityVest(activeUnit, vestId, effectId, effectLevel, hurtType);
            }
            unit.issueImmediateOrder(strOrder)
        } else if (cast_type1 === CastType1.unit) {
            targetArr.forEach(
                (value, index, array) => {
                    Logger.toastSkill(`马甲对单位释放`, player)
                    const enumUnit = value;
                    if (enumUnit?.isAlive()) {
                    } else {
                        Logger.toastSkill(`单位已死亡，停止释放`, player)
                        return;
                    }
                    if (vestId) {
                        unit = TriggerUtil.createAbilityVest(activeUnit, vestId, effectId, effectLevel, hurtType);
                    }
                    unit.issueTargetOrder(strOrder, enumUnit);
                }
            )
        } else if (cast_type1 === CastType1.point) {
            targetLocArr.forEach(
                (loc, index, array) => {
                    Logger.toastSkill(`马甲对点释放`, player)
                    Logger.toastSkill(`马甲释放点 X:${loc.x} Y:${loc.y}`, player)
                    if (vestId) {
                        unit = TriggerUtil.createAbilityVest(activeUnit, vestId, effectId, effectLevel, hurtType);
                    }
                    unit.issueOrderAt(strOrder, loc)
                }
            )
        } else {
            Logger.toastError(`${abilityId}技能无法通过触发释放`);
        }
    }
    static abilityAddChangeAttribute = (activeUnit: UnitModel, activePlayer: PlayerModel, attribute: UnitAttribute, currentAttribute: UnitAttribute, targetAttribute: UnitAttribute, targetAttr: AttributeEnum, sourceAttr: AttributeEnum, value: number, percentage: number, addTimes: number, effectLevel: number, targetAddIsMine: number, effectId: string): UnitAttribute => {
        // 当前属性
        if (!CodeUtil.isNullOrZero(value)) {
        } else {
            Logger.toastError(`技能效果 ${effectId} 所增益的值不能为空`);
            return;
        }
        Logger.toastSkill(`增益：start`, activePlayer);
        let newValue = value * effectLevel * addTimes;
        let bAlways = false;
        // 属性增益系统只能对属性系统的单位生效
        // let bAlways = ture;
        // const isHero = UnitController.getInstance().isAttributeUnit(activeUnit);
        // if (isHero) {
        //     bAlways = false;
        // }
        Logger.toastSkill(`bAlways：${bAlways}`, activePlayer);
        if (!CodeUtil.isNullOrZero(targetAddIsMine)) {
            Util.caluAbilityAttr(activeUnit,activePlayer, currentAttribute, currentAttribute, attribute, targetAttr, sourceAttr,  newValue,  percentage,  CaluType.set, true, bAlways, effectId);
        } else {
            Util.caluAbilityAttr(activeUnit,activePlayer, targetAttribute, currentAttribute, attribute, targetAttr, sourceAttr,  newValue,  percentage,  CaluType.set, true, bAlways, effectId);
        }
        Logger.toastSkill(`增益：end`, activePlayer);
        return attribute;
    }
    static abilityTheftChangeAttribute = (activeUnit: UnitModel, activePlayer: PlayerModel, attribute: UnitAttribute, currentAttribute: UnitAttribute, targetAttribute: UnitAttribute, originallyAttribute: UnitAttribute, targetAttr: AttributeEnum, sourceAttr: AttributeEnum, value: number, percentage: number, effectLevel: number, theftSourceIsMine: number, effectId: string) => {
        let newValue = value * effectLevel;
        const player = PlayerFactory.getInstance().getUnitOwner(activeUnit);
        Logger.toastSkill(`奖励：start`, player);
        const bAlways = TriggerUtil.getIsBAlways(targetAttr);
        if (!CodeUtil.isNullOrZero(theftSourceIsMine)) {
            Util.caluAbilityAttr(activeUnit,activePlayer, currentAttribute, originallyAttribute, attribute, targetAttr, sourceAttr,  newValue,  percentage,  CaluType.add, false, bAlways, effectId);
        } else {
            Util.caluAbilityAttr(activeUnit,activePlayer, targetAttribute, originallyAttribute, attribute, targetAttr, sourceAttr,  newValue,  percentage,  CaluType.add, false, bAlways, effectId);
        }
        Logger.toastSkill(`奖励：end`, player);
        return attribute;
    }
    static getIsBAlways = (targetAttr: AttributeEnum) => {
        if (targetAttr) {
        } else {
            return false;
        }
        const arr = [
            AttributeEnum.strength,
            AttributeEnum.agile,
            AttributeEnum.intellect,
            AttributeEnum.life,
            AttributeEnum.maxLife,
            AttributeEnum.lifeRecovery,
            AttributeEnum.magic,
            AttributeEnum.maxMagic,
            AttributeEnum.magicRecovery,

            // AttributeEnum.defense,
            // AttributeEnum.attack,
            AttributeEnum.attackSpeed,

            AttributeEnum.speed,
            AttributeEnum.coin,
            AttributeEnum.wood,
            AttributeEnum.exp,
            AttributeEnum.attackDistance,
            AttributeEnum.size,
        ]
        const index = arr.indexOf(targetAttr);
        if (index >= 0) {
            return true
        }
        return false;
    }
    // -------------------------------------------------------------------------------------------------------------------------------------------------

}
